<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>程序包管理</title>
    <link rel="stylesheet" href="/css/bootstrap.min.css">
    <link rel="stylesheet" href="/css/bootstrap-table.min.css">
    <link rel="stylesheet" href="/css/pub.css">
    <link rel="stylesheet" href="/css/jquery-confirm.min.css">
    <link rel="stylesheet" href="/css/font-awesome-all.min.css">
    <style>
        .container {
            width: 100% !important;
            max-width: 100% !important;
            margin: 20px auto;
            padding: 4px;
        }

        .split-layout {
            display: flex;
            flex-direction: column;
            gap: 20px;
            margin-top: 20px;
        }

        .panel {
            flex: 1;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background: #fff;
        }

        .panel-title {
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }

        .job-list {
            margin-top: 15px;
        }

        .status-running {
            color: #28a745;
        }

        .status-stopped {
            color: #dc3545;
        }

        .form-group {
            margin-bottom: 15px;
            display: flex;
            height: 40px;
        }

        .form-group label {
            width: 140px;
            line-height: 40px;
        }

        .form-group .form-input {
            flex: 1;
        }

        .form-group button {
            width: 100px;
            margin-left: 10px;
        }

        /* @media (max-width: 768px) {
            .split-layout {
                flex-direction: column;
            }
        } */
    </style>
</head>

<body>
    <div class="container">
        <div class="split-layout">
            <!-- 左侧：Flink服务连接表单 -->
            <div class="panel">
                <div class="form-group">
                    <label>Flink REST地址</label>
                    <div class="form-input">
                        <input type="text" class="form-control" id="url" placeholder="请输入Flink服务器地址，空则使用服务端设置">
                    </div>
                    <button class="btn btn-primary" id="btnQueryJar" onclick="onClickQueryJarList()"><i
                            class="fa-solid fa-magnifying-glass-plus"></i>查询</button>
                    <button class="btn btn-danger" id="btnQueryJar" onclick="onClickUploadJar()"><i
                            class="fa-solid fa-cloud-arrow-up"></i>上传</button>
                </div>
            </div>

            <!-- 右侧：Jar任务列表 -->
            <div class="panel">
                <h3 class="panel-title">Jar任务列表</h3>
                <div class="job-list">
                    <table id="jarTable">
                    </table>
                </div>
            </div>
        </div>


        <!-- JAR上传弹窗 -->
        <div class="modal fade" id="uploadJarModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">上传JAR文件</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <div class="upload-container text-center">
                            <div class="upload-icon mb-3">
                                <i class="fas fa-cloud-upload-alt fa-4x text-primary"></i>
                            </div>
                            <p class="mb-3">请选择要上传的JAR文件</p>
                            <input type="file" id="jarFileInput" class="d-none" accept=".jar">
                            <button class="btn btn-primary" id="selectJarBtn">选择文件</button>
                            <div class="progress mt-3 d-none" id="uploadProgress">
                                <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
                                    style="width: 0%"></div>
                            </div>
                            <div class="upload-status mt-3"></div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" id="cancelUploadBtn"
                            data-bs-dismiss="modal">取消</button>
                        <button type="button" class="btn btn-primary" id="startUploadBtn" disabled>开始上传</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 运行作业配置弹窗 -->
        <div class="modal fade" id="jobConfigModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">作业配置</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <form id="jobConfigForm">
                            <div class="mb-3">
                                <label class="form-label">作业名称</label>
                                <input type="text" class="form-control" id="jobName" required>
                            </div>
                            <div class="mb-3">
                                <label class="form-label">Artemis密码</label>
                                <input type="password" class="form-control" id="artemisPassword" required>
                            </div>
                            <div class="mb-3">
                                <label class="form-label">MySQL密码</label>
                                <input type="password" class="form-control" id="mysqlPassword" required>
                            </div>
                        </form>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <button type="button" class="btn btn-primary" id="confirmJobConfig">确定</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="/js/jquery-3.7.1.js"></script>
    <script src="/js/bootstrap.bundle.min.js"></script>
    <script src="/js/bootstrap-table.min.js"></script>
    <script src="/js/jquery-confirm.min.js"></script>
    <script src="/js/pub.js"></script>
    <script src="/js/flink.js"></script>
    <script src="/js/font-awesome-all.min.js" data-auto-replace-svg="nest"></script>
    <script>
        const format = new JarFormatter();
        var selectBtnClickFun=null;
        var fileInputChangeFun=null;
        var startBtnClickFun=null;

        //调用jquery的初始化方法
        $(function () {
            init();
        });

        function init() {
            $('#jarTable').bootstrapTable(
                {
                    ajax: function (params) {
                        $.ajax({
                            url: "/flink/jars/getJars?url=" + $("#url").val(),
                            type: "GET",
                            headers: {
                                "auth2045": getLoginToken()
                            },
                            contentType: "application/json",
                            async: true,
                            success: function (rs, status, xhr) {
                                let r = JSON.parse(rs.data);
                                let files = r.files;
                                params.success({
                                    "total": files.length,
                                    "rows": files
                                },
                                    "ok",
                                    xhr
                                );
                            },
                            error: function (jqXHR, textStatus, errorThrown) {
                                $.alert({
                                    title: '警告',
                                    content: "查询失败，网络错误:" + textStatus,
                                    type: 'red',
                                    buttons: {
                                        ok: {
                                            text: '确定',
                                            btnClass: 'btn-primary'
                                        }
                                    }
                                });
                                params.success({
                                    "total": 0,
                                    "rows": []
                                },
                                    "ok",
                                    jqXHR
                                );
                            }
                        });
                    },
                    resizable: true,
                    pagination: true,
                    search: true,
                    sidePagination: 'client',
                    columns: [
                        { field: 'id', title: '程序包ID' },
                        { field: 'name', title: '名称' },
                        { title: '入口', formatter: format.entryFormatter },
                        { field: 'uploaded', title: '上传时间', formatter: format.uploadedFormatter },
                        { title: '操作', formatter: format.operateFormatter, with: 200, align: 'center' }
                    ],
                }
            );
        }

        function onClickQueryJarList() {
            $('#jarTable').bootstrapTable('refresh');
        }

        /**
         * 文件上传
         */
        function onClickUploadJar() {
            const uploadModal = new bootstrap.Modal(document.getElementById('uploadJarModal'));
            const fileInput = document.getElementById('jarFileInput');
            const selectBtn = document.getElementById('selectJarBtn');
            const startBtn = document.getElementById('startUploadBtn');
            const progressBar = document.getElementById('uploadProgress');
            const uploadStatus = document.querySelector('.upload-status');
            // 重置状态
            fileInput.value = '';
            selectBtn.disabled = false;
            startBtn.disabled = true;
            progressBar.classList.add('d-none');
            uploadStatus.innerHTML = '';

            //1.0 重置事件监听器，防止重复绑定导致多次触发事件
            if (selectBtnClickFun !== null) {
                selectBtn.removeEventListener('click', selectBtnClickFun);
            }
            // 选择文件按钮点击事件
            selectBtnClickFun = function () {
                fileInput.click();
            };
            selectBtn.addEventListener('click', selectBtnClickFun);

            //2.0 文件选择变化事件

            if (fileInputChangeFun !== null) {
                fileInput.removeEventListener('change', fileInputChangeFun);
            }

            fileInputChangeFun = function (e) {
                if (this.files.length > 0) {
                    const file = this.files[0];
                    if (!file.name.endsWith('.jar')) {
                        uploadStatus.innerHTML = '<div class="alert alert-danger">请选择JAR文件</div>';
                        startBtn.disabled = true;
                    } else {
                        uploadStatus.innerHTML = `<div class="alert alert-info">已选择: ${file.name} (${(file.size / 1024 / 1024).toFixed(2)} MB)</div>`;
                        startBtn.disabled = false;
                    }
                }
            };
            fileInput.addEventListener('change', fileInputChangeFun);


            //3.0 开始上传按钮点击事件
            if (startBtnClickFun !== null) {
                startBtn.removeEventListener('click', startBtnClickFun);
            }
            startBtnClickFun = function () {
                if (!fileInput.files.length){
                    //恢复有关按钮状态
                    selectBtn.disabled = false;
                    startBtn.disabled = true;
                    return;
                }


                const file = fileInput.files[0];
                const formData = new FormData();
                formData.append('file', file);

                // 禁用按钮并显示进度条
                startBtn.disabled = true;
                selectBtn.disabled = true;
                document.getElementById('cancelUploadBtn').disabled = true;
                progressBar.classList.remove('d-none');
                const progress = progressBar.querySelector('.progress-bar');
                progress.style.width = '0%';
                uploadStatus.innerHTML = '<div class="alert alert-info">上传中，请稍候...</div>';

                // 使用AJAX上传以便获取进度
                const xhr = new XMLHttpRequest();
                xhr.open('POST', '/flink/jars/upload?url=' + $("#url").val(), true);
                xhr.setRequestHeader("auth2045", getLoginToken());

                // 上传进度事件
                xhr.upload.addEventListener('progress', function (e) {
                    if (e.lengthComputable) {
                        const percentComplete = Math.round((e.loaded / e.total) * 100);
                        progress.style.width = percentComplete + '%';
                    }
                });

                xhr.onload = function () {
                    if (xhr.status === 200) {
                        const resp = JSON.parse(xhr.response);
                        if (resp.flag === 1) {
                            let fileInfo = JSON.parse(resp.data);
                            if (fileInfo.status == "success") {
                                uploadStatus.innerHTML = '<div class="alert alert-success">上传成功!</div>';
                                setTimeout(() => {
                                    uploadModal.hide();
                                    $('#jarTable').bootstrapTable('refresh');
                                }, 1000);
                            } else {
                                uploadStatus.innerHTML = `<div class="alert alert-danger">上传失败: ${resp.message}</div>`;
                                startBtn.disabled = false;
                                selectBtn.disabled = false;
                            }
                        } else {
                            uploadStatus.innerHTML = `<div class="alert alert-danger">上传失败: ${resp.message}</div>`;
                            startBtn.disabled = false;
                            selectBtn.disabled = false;
                        }
                    } else {
                        uploadStatus.innerHTML = '<div class="alert alert-danger">上传失败: 网络错误</div>';
                        startBtn.disabled = false;
                        selectBtn.disabled = false;
                    }
                    document.getElementById('cancelUploadBtn').disabled = false;
                };

                xhr.onerror = function () {
                    uploadStatus.innerHTML = '<div class="alert alert-danger">上传失败: 网络错误</div>';
                    startBtn.disabled = false;
                    selectBtn.disabled = false;
                    document.getElementById('cancelUploadBtn').disabled = false;
                };

                xhr.send(formData);
            };

            startBtn.addEventListener('click', startBtnClickFun);

            uploadModal.show();
        }

        function removeJar(jarId) {
            $.confirm({
                title: '确认删除程序包',
                content: '确定要删除这个Jar吗？此操作不可撤销！',
                type: 'orange',
                buttons: {
                    confirm: {
                        text: '确定删除',
                        btnClass: 'btn-danger',
                        action: function () {
                            $.ajax({
                                url: "/flink/jars/delete/" + jarId + "?url=" + $("#url").val(),
                                type: "GET",
                                headers: {
                                    "auth2045": getLoginToken()
                                },
                                contentType: "application/json",
                                async: true,
                                success: function (rs, status, xhr) {
                                    if (rs.data) {
                                        showMessage('操作成功', 'Jar已删除', 'success');
                                        $('#jarTable').bootstrapTable('refresh');
                                    }
                                    else {
                                        showMessage('操作失败', rs.message || '删除失败', 'error');
                                    }
                                },
                                error: function (jqXHR, textStatus, errorThrown) {
                                    showMessage('网络错误', '取消失败: ' + textStatus, 'error');
                                }
                            });
                        }
                    },
                    cancel: {
                        text: '取消',
                        btnClass: 'btn-secondary'
                    }
                }
            });
        }

        function runJar(config) {
            $.ajax({
                url: "/flink/jars/run",
                type: "POST",
                headers: {
                    "auth2045": getLoginToken()
                },
                contentType: "application/json",
                data: JSON.stringify(config),
                async: false,
                success: function (rs, status, xhr) {
                    if (rs.flag == 1) {
                        showMessage('操作成功', 'Jar已运行', 'success');
                        $('#jarTable').bootstrapTable('refresh');
                    }
                    else {
                        showMessage('操作失败', rs.message || '运行失败', 'error');
                    }
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    showMessage('网络错误', '取消失败: ' + textStatus, 'error');
                }
            });
        }


        // 显示配置弹窗函数
        function showJobConfig(jarId) {
            const modal = new bootstrap.Modal(document.getElementById('jobConfigModal'));
            // 重置表单
            //$('#jobConfigForm')[0].reset();

            $('#confirmJobConfig').off('click').on('click', function () {
                if ($('#jobConfigForm')[0].checkValidity()) {
                    const config = {
                        "jarId": jarId,
                        "serverUrl": $("#url").val(),
                        "jobName": $('#jobName').val(),
                        "programArgs": [$('#artemisPassword').val(), $('#mysqlPassword').val()]
                    };
                    modal.hide();
                    runJar(config);
                } else {
                    $('#jobConfigForm')[0].reportValidity();
                }
            });
            modal.show();
        }
    </script>

</html>